#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "QTcpServer"
#include "QLabel"
#include "QHostInfo"
#include "QTcpSocket"

MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    labListen = new QLabel("监听状态");
    labListen->setMinimumWidth(150);
    ui->statusBar->addWidget(labListen);
    labSocketState = new QLabel("socket 状态：");
    labSocketState->setMinimumWidth(200);
    ui->statusBar->addWidget(labSocketState);

    QString localIPv4 = getLocalIPv4(); // 获取本机 IP 地址
    this->setWindowTitle(this->windowTitle() + "----本机 IP 地址：" + localIPv4);
    ui->comboIP->addItem(localIPv4);

    tcpServer = new QTcpServer(this);
    connect(tcpServer, &QTcpServer::newConnection, this, &MainWindow::do_newConnection);

    // “开始监听”按钮
    connect(ui->actStart, &QAction::triggered, this, [this]() {
        QString IP = ui->comboIP->currentText(); // IP 地址字符串，如"127.0.0.1"
        uint16_t port = ui->spinPort->value();   // 端口
        qDebug() << "开始监听 " << IP << "  " << port;
        QHostAddress address(IP); // 通过 IP 地址字符串创建 QHostAddress 对象
        /*作为 TCP 服务器，QTcpServer 对象需要调用函数 listen()在本机某个 IP 地址和端口上开始 TCP 监听，以等待 TCP 客户端的接入。*/
        tcpServer->listen(address, port);
        ui->textEdit->appendPlainText("**开始监听...");
        ui->textEdit->appendPlainText("**服务器地址：" + tcpServer->serverAddress().toString());
        ui->textEdit->appendPlainText("**服务器端口：" + QString::number(tcpServer->serverPort()));
        ui->actStart->setEnabled(false);
        ui->actStop->setEnabled(true);
        labListen->setText("监听状态：正在监听");
    });

    // “停止监听”按钮
    connect(ui->actStop, &QAction::triggered, this, [this]() {
        if (tcpServer->isListening()) // tcpServer 正在监听
        {
            if (tcpSocket != nullptr)
            {
                if (tcpSocket->state() == QAbstractSocket::ConnectedState)
                {
                    tcpSocket->disconnectFromHost(); // 向对方发送“关闭请求”，开始断开 TCP 连接。
                }
            }
            tcpServer->close(); // 停止监听
            ui->actStart->setEnabled(true);
            ui->actStop->setEnabled(false);
            labListen->setText("监听状态：已停止监听");
        }
    });

    // “发送消息”按钮，发送一行字符串，以换行符结束
    connect(ui->btnSend, &QToolButton::clicked, this, [this]() {
        QString msg = ui->editMsg->text();
        ui->textEdit->appendPlainText("【发送】 " + msg);
        ui->editMsg->clear();
        msg += '\n';
        QByteArray sendData = msg.toUtf8();
        tcpSocket->write(sendData);
    });
}

MainWindow::~MainWindow()
{
    if (tcpSocket != nullptr)
    {
        if (tcpSocket->state() == QAbstractSocket::ConnectedState)
        {
            tcpSocket->disconnectFromHost(); // 断开与客户端的连接
        }
    }
    if (tcpServer->isListening())
    {
        tcpServer->close(); // 停止网络监听
    }

    delete ui;
}

QString MainWindow::getLocalIPv4()
{
    QString hostName = QHostInfo::localHostName(); // 本机主机名
    QHostInfo hostInfo = QHostInfo::fromName(hostName);
    QString localIPv4 = "";
    QList<QHostAddress> addrList = hostInfo.addresses(); // 本机 IP 地址列表
    if (addrList.isEmpty())
        return localIPv4;
    for (const auto& aHost : addrList)
    {
        if (aHost.protocol() == QAbstractSocket::IPv4Protocol)
        {
            localIPv4 = aHost.toString();
            break;
        }
    }
    return localIPv4;
}

void MainWindow::do_clientConnected()
{
    qDebug() << "do_clientConnected";
    ui->textEdit->appendPlainText("**客户端套接字连接");
    ui->textEdit->appendPlainText("**对方地址：" + tcpSocket->peerAddress().toString());
    ui->textEdit->appendPlainText("**对方端口：" + QString::number(tcpSocket->peerPort()));
}

void MainWindow::do_clientDisconnected()
{
    qDebug() << "do_clientDisconnected";
    ui->textEdit->appendPlainText("**客户端套接字断开");
    tcpSocket->deleteLater();
}

void MainWindow::do_socketStateChanged(QAbstractSocket::SocketState socketState)
{
    qDebug() << "do_socketStateChanged";
    QString state = "";
    switch (socketState)
    {
    case QAbstractSocket::SocketState::UnconnectedState:
        state = "UnconnectedState";
        break;
    case QAbstractSocket::SocketState::HostLookupState:
        state = "HostLookupState";
        break;
    case QAbstractSocket::SocketState::ConnectingState:
        state = "ConnectingState";
        break;
    case QAbstractSocket::SocketState::ConnectedState:
        state = "ConnectedState";
        break;
    case QAbstractSocket::SocketState::BoundState:
        state = "BoundState";
        break;
    case QAbstractSocket::SocketState::ListeningState:
        state = "ListeningState";
        break;
    case QAbstractSocket::SocketState::ClosingState:
        state = "ClosingState";
        break;
    default:
        break;
    }
    labSocketState->setText(state);
}

void MainWindow::do_newConnection()
{
    qDebug() << "do_newConnection";
    tcpSocket = tcpServer->nextPendingConnection(); // 创建 socket
    connect(tcpSocket, &QTcpSocket::connected, this, &MainWindow::do_clientConnected);
    do_clientConnected(); // 运行一次槽函数，显示状态
    connect(tcpSocket, &QTcpSocket::disconnected, this, &MainWindow::do_clientDisconnected);
    connect(tcpSocket, &QTcpSocket::stateChanged, this, &MainWindow::do_socketStateChanged);
    do_socketStateChanged(tcpSocket->state()); // 运行一次槽函数，显示状态

    connect(tcpSocket, &QTcpSocket::readyRead, this, &MainWindow::do_socketReadyRead);
}

void MainWindow::do_socketReadyRead()
{
    qDebug() << "do_socketReadyRead";
    // // 判断当前 TCP 套接字的接收缓冲区中是否有一整行数据可以读取。
    // while (tcpSocket->canReadLine())//必须以换行符结尾 只有在收到完整的一行（以 \n 或 \r\n 结尾）时才会返回数据。
    // {
    //     QString received = tcpSocket->readLine();
    //     qDebug()<<"received "<<received;
    //     // 读取缓冲区的行文本
    //     ui->textEdit->appendPlainText("【收到】 " + received);
    // }

    QByteArray data = tcpSocket->readAll(); // 读取所有可用数据
    qDebug() << "原始数据  " << data;
    // 如果是文本，可以尝试按行分割
    QStringList lines = QString::fromUtf8(data).split('\n');
    for (const QString& line : lines)
    {
        if (!line.isEmpty())
        {
            ui->textEdit->appendPlainText("【收到】 " + line);
        }
    }
}
